#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest/doctest.h"

#include "klib/format.hpp"
#include <cassert>

using namespace klib;

TEST_CASE("format") {
    SUBCASE("format_use_fn") {
        uint8_t u8 = (uint8_t) -1;
        uint32_t i32 = (uint32_t) -1;
        uint64_t i64 = (uint64_t) -1;
        std::string s = "i8 = -1, 255, i32 = -1, 4294967295, i64 = -1, 18446744073709551615, d = 25.34, b = false,true";
        struct A { char data[256]; size_t pos; } a {{0}, 0};
        size_t size = fmt::format(&a, +[](A* arg, const char* data, size_t size) {
            CHECK(arg->pos + size < 256);
            std::memcpy(arg->data + arg->pos, data, size);
            arg->pos += size;
        }, "i8 = {}, {}, i32 = {}, {}, i64 = {}, {}, d = {}, b = {},{}",
                (int32_t) (int8_t) u8, (uint32_t) u8, (int32_t) i32, i32, (int64_t) i64, i64, 25.34, false, true);
        CHECK(size == s.size());
        CHECK(s == std::string(a.data, a.pos));
    }

    SUBCASE("format_use_buf") {
        time_t t = 1657390330; // 2022-07-10 02:12:10
        tm tm_ = *localtime(&t);
        std::string s = "2022-07-10 02:12:10, 2022-07-10 02:12:10, {}";
        char buf[256];
        size_t size = fmt::format(buf, sizeof(buf), "{}, {}, {}", packtime_t(t), tm_);
        CHECK(size == s.size());
        CHECK(s == std::string(buf, size));
    }

    SUBCASE("format_use_append") {
        time_t t = 1657390330; // 2022-07-10 02:12:10
        tm tm_ = *localtime(&t);
        std::string a1("kiven");
        std::string s = "2022-07-10 02:12:10, kiven";
        std::string ret;
        size_t size = fmt::format(ret, "{}, {}", tm_, a1);
        CHECK(size == s.size());
        CHECK(s == ret);
        size = fmt::format(ret, "{}", "lee");
        CHECK(size == 3);
        s.append("lee");
        CHECK(s == ret);
    }

    SUBCASE("format_use_append") {
        time_t t = 1657390330; // 2022-07-10 02:12:10
        tm tm_ = *localtime(&t);
        std::string a1("kiven");
        std::string s = "2022-07-10 02:12:10, kiven";
        fmt::fmt_arg_t args[] = {tm_, a1};
        std::string ret;
        size_t size = fmt::vformat(ret, "{}, {}", args);
        CHECK(size == s.size());
        CHECK(s == ret);
        size = fmt::format(ret, "{}", "lee");
        CHECK(size == 3);
        s.append("lee");
        CHECK(s == ret);
    }

    SUBCASE("format_len") {
        time_t t = 1657390330; // 2022-07-10 02:12:10
        tm tm_ = *localtime(&t);
        std::string a1("kiven");
        std::string s = "2022-07-10 02:12:10, kiven";
        fmt::fmt_arg_t args[] = {tm_, a1};
        size_t size = fmt::format_len("{}, {}", tm_, a1);
        CHECK(size == s.size());
        size = fmt::vformat_len("{}, {}", args);
        CHECK(size == s.size());
    }

    SUBCASE("format_string") {
        time_t t = 1657390330; // 2022-07-10 02:12:10
        tm tm_ = *localtime(&t);
        std::string a1("kiven");
        std::string s = "2022-07-10 02:12:10, kiven";
        std::string ret;
        size_t size = fmt::format_append(ret, "{}, {}", tm_, a1);
        CHECK(size == s.size());
        CHECK(ret.size() == s.size());
        CHECK(ret == s);
        ret = fmt::format_string("{}, {}", tm_, a1);
        CHECK(ret.size() == s.size());
        CHECK(ret == s);
    }

    SUBCASE("format_alloc") {
        time_t t = 1657390330; // 2022-07-10 02:12:10
        tm tm_ = *localtime(&t);
        std::string a1("kiven");
        std::string s = "2022-07-10 02:12:10, kiven";
        std::string ret;
        auto sv = fmt::format_alloc([&ret] (size_t size) mutable {
            ret.resize(size);
            return ret.data();
        }, "{}, {}", tm_, a1);
        CHECK(sv.size() == s.size());
        CHECK(ret.size() == s.size());
        CHECK(ret == s);
    }
}